﻿using Api_Core_Spider.Data;
using Api_Core_Spider.Models;
using System.Security.Cryptography;
using System.Text.RegularExpressions;
using System.Text;
using Microsoft.EntityFrameworkCore;
using System.Security;

namespace Api_Core_Spider.Services
{
    //public interface IActivationService
    //{
    //    bool IsActivated(MachineInfo machineInfo); //校验是否激活
    //    Task<bool> Activate(ActivationRequest request); //激活方法
    //    MachineInfo GetMachineInfo(); ///获取当前机器信息
    //}
    /// <summary>
    /// 激活服务实现，处理软件激活相关业务逻辑
    /// </summary>
    public class ActivationService : IActivationService
    {
        private readonly IConfiguration _configuration;
        private readonly ILogger<ActivationService> _logger;
        private readonly ActivationDbContext _dbContext;
        private readonly string _encryptionKey = "YourSecretKey12345mxf"; // 应从安全存储中获取
        private readonly IMachineCodeGenerator _machineCodeGenerator;
        // 密钥长度常量定义（字节）
        private const int AesKeySize128 = 16;
        private const int AesKeySize192 = 24;
        private const int AesKeySize256 = 32;
        private static readonly byte[] FixedKey = new byte[32];
        static ActivationService()
        {
            FixedKey = GenerateKey();
            RandomNumberGenerator.Fill(FixedKey);
        }

        public ActivationService(ActivationDbContext dbContext, ILogger<ActivationService> logger, IConfiguration configuration, IMachineCodeGenerator machineCodeGenerator)
        {
            _configuration = configuration;
            _logger = logger;
            _dbContext = dbContext;
            _machineCodeGenerator = machineCodeGenerator;
        }

        /// <summary>
        /// 执行激活流程 处理激活请求
        /// </summary>
        /// <param name="request">激活请求</param>
        /// <returns>激活响应</returns>
        public ActivationResponse Activate(ActivationRequest request)
        {
            var response = new ActivationResponse { Success = false };

            try
            {
                // 验证产品密钥
                if (!IsValidProductKey(request.ProductKey))
                //if (!IsValidProductKey(FormatKey(request.ProductKey,true)))
                {
                    response.ErrorMessage = "无效的产品密钥";
                    return response;
                }

                // 1. 解析产品密钥
                var keyInfo = ParseProductKey(request.ProductKey);

                //2. 查询数据库 检查产品密钥是否已被使用
                var existingActivation = _dbContext.Activations
                    .FirstOrDefault(a => a.ProductKey == request.ProductKey);

                if (existingActivation != null)
                {
                    // 3.  检查是否允许重复激活
                    if (!keyInfo.AllowMultiActivation)
                    {
                        response.ErrorMessage = "此产品密钥已被使用";
                        return response;
                    }
                }

                // 生成激活码
                string activationCode = GenerateActivationCode(request.MachineInfo.MachineCode, request.ProductKey);

                // 计算过期日期
                DateTime expireDate = DateTime.Now.AddDays(keyInfo.ValidDays);

                // 4. 保存激活信息
                var activation = new Activation
                {
                    MachineCode = request.MachineInfo.MachineCode,
                    ProductKey = request.ProductKey,
                    ActivationCode = activationCode,
                    UserName = request.UserName,
                    Email = request.Email,
                    ActivatedDate = DateTime.Now,
                    ExpireDate = expireDate,
                    IsActive = true
                };

                _dbContext.Activations.Add(activation);
                _dbContext.SaveChanges();

                // 5.  返回成功构建成功响应
                response.Success = true;
                response.ActivationCode = activationCode;
                response.ExpireDate = expireDate.ToString("yyyy-MM-dd");
                response.ErrorMessage = "激活成功";

                return response;
            }
            catch (Exception ex)
            {
                response.ErrorMessage = $"激活过程中发生错误: {ex.Message}";
                return response;
            }
        }
        /// <summary>
        /// 验证激活码
        /// </summary>
        /// <param name="request">验证请求</param>
        /// <returns>验证响应</returns>
        public ValidationResponse Validate(ValidationRequest request)
        {
            var response = new ValidationResponse { IsValid = false };

            try
            {
                // 查找激活记录
                var activation = _dbContext.Activations
                    .FirstOrDefault(a => a.MachineCode == request.MachineCode &&
                                        a.ActivationCode == request.ActivationCode);

                if (activation == null)
                {
                    response.ErrorMessage = "未找到匹配的激活记录";
                    return response;
                }

                // 检查是否过期
                bool isExpired = activation.ExpireDate < DateTime.Now;

                // 构建响应
                response.IsValid = !isExpired && activation.IsActive;
                response.IsExpired = isExpired;
                response.RemainingDays = (int)(activation.ExpireDate - DateTime.Now).TotalDays;

                return response;
            }
            catch (Exception ex)
            {
                response.ErrorMessage = $"验证过程中发生错误: {ex.Message}";
                return response;
            }
        }

        /// <summary>
        /// 生成产品密钥
        /// </summary>
        /// <param name="productId">产品ID</param>
        /// <param name="userId">用户ID</param>
        /// <param name="days">有效期天数</param>
        /// <returns>产品密钥</returns>
        public string GenerateProductKey(string productId, string userId, int days)
        {
            // 产品密钥格式: 版本-产品ID-用户ID-有效期-校验和
            string baseKey = $"1-{productId}-{userId}-{days}-{Guid.NewGuid().ToString("N").Substring(0, 8)}";

            // 加密
            //string encryptedKey = Encrypt(baseKey); // 生成不含+、/、的字符串
            string  encryptedKey = EncryptWithAesGcm(baseKey, FixedKey);
            // 格式化为易读形式
            //string formattedkey = FormatKey(encryptedKey); // 格式化后："abcde-fghij-klmno-pqrst-uvwxy"
            return encryptedKey;
        }

        /// <summary>
        /// 生成激活码
        /// </summary>
        /// <param name="machineCode">机器码</param>
        /// <param name="productKey">产品密钥</param>
        /// <returns>激活码</returns>
        public string GenerateActivationCode(string machineCode, string productKey)
        {
            // 组合机器码和产品密钥
            //string combined = $"{machineCode}{Decrypt(FormatKey(productKey, true))}";
            string combined = $"{machineCode}{DecryptWithAesGcm(productKey,FixedKey)}";

            // 使用HMAC-SHA256生成哈希
            using (HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(_encryptionKey)))
            {
                byte[] hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(combined));

                // 转换为Base64并替换不适合URL的字符
                string activationCode = Convert.ToBase64String(hashBytes)
                    .Replace('+', '-')
                    .Replace('/', '_')
                    .TrimEnd('=');

                // 格式化为易读形式
                //return FormatKey(activationCode);
                return activationCode;
            }
        }
        /// <summary>
        /// 验证产品密钥
        /// </summary>
        private bool IsValidProductKey(string productKey)
        {
            try
            {
                ////1.验证格式：5组连字符分隔，最后一组可能包含等号
                //string pattern = @"([A-Za-z0-9-_]{5}-){4}[A-Za-z0-9-_]{2,3}={0,2}";
                //if (!Regex.IsMatch(productKey, pattern))
                //{
                //    return false;
                //}

                // 2. 解密并解析
                //string decrypted = Decrypt(productKey);
                //string decrypted = DecryptWithAesGcm(FormatKey(productKey,true),GenerateKey());
                string decrypted = DecryptWithAesGcm(productKey, FixedKey);
                string[] parts = decrypted.Split('-');

                if (parts.Length != 5)
                {
                    return false;
                }

                // 3. 验证版本
                if (parts[0] != "1")
                {
                    return false;
                }

                // 4. 验证有效期（应为正整数）
                if (!int.TryParse(parts[3], out int days) || days <= 0)
                {
                    return false;
                }

                // 5. 验证校验和（当前未实现，建议添加）
                // if (!VerifyChecksum(parts)) return false;

                return true;
            }
            catch
            {
                return false;
            }
        }
        /// <summary>
        /// 验证是否激活
        /// </summary>
        /// <param name="machineInfo"></param>
        /// <returns></returns>
        // 核心：校验是否激活（可结合 machineInfo 做更严格校验）
        public async Task<bool> IsActivated(MachineInfo machineInfo)
        {
            // 1. 基础校验：激活标记 + 系统信息匹配
            string machineCode = _machineCodeGenerator.GenerateMachineCode();

            // 2. 可扩展：校验激活有效期、授权范围等
            return await _dbContext.Activations
                .AnyAsync(a => a.MachineCode == machineCode &&
                           a.IsActive);
        }
        /// <summary>
        /// 解析产品密钥
        /// </summary>
        /// <param name="productKey"></param>
        /// <returns></returns>
        private (string ProductId, string UserId, int ValidDays, bool AllowMultiActivation) ParseProductKey(string productKey)
        {
            //string decrypted = Decrypt(FormatKey(productKey, true));
            string decrypted = DecryptWithAesGcm(productKey, FixedKey);
            string[] parts = decrypted.Split('-');

            return (
                ProductId: parts[1],
                UserId: parts[2],
                ValidDays: int.Parse(parts[3]),
                AllowMultiActivation: false // 可扩展为从密钥中解析此信息
            );
        }
        // 加密方法
        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="plainText"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public string Encrypt(string plainText)
        {
            if (string.IsNullOrEmpty(plainText))
                throw new ArgumentNullException(nameof(plainText));

            // 1. 生成正确的256位密钥（32字节秘钥）
            var keyBytes = GetValidKeyBytes(_encryptionKey, AesKeySize256);

            using var aesAlg = Aes.Create();
            aesAlg.Key = keyBytes;
            aesAlg.GenerateIV();
            aesAlg.Mode = CipherMode.CBC;        // 显式设置模式
            aesAlg.Padding = PaddingMode.PKCS7;  // 强制使用PKCS7填充

            using var encryptor = aesAlg.CreateEncryptor();
            using var msEncrypt = new MemoryStream();

            // 2. 写入IV（16字节）
            msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length);

            // 3. 加密数据并确保填充正确
            using var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
            using var swEncrypt = new StreamWriter(csEncrypt);
            swEncrypt.Write(plainText);
            swEncrypt.Flush();

            // 4. 获取完整密文（IV + 加密数据）
            byte[] cipherBytes = msEncrypt.ToArray();

            // 5. 转换为URL安全Base64（保留必要填充）
            string base64 = Convert.ToBase64String(cipherBytes);
            string urlSafeBase64 = base64
                .Replace('+', '-')
                .Replace('/', '_')
                .TrimEnd('=');  // 仅移除无意义的填充

            return urlSafeBase64;
        }
        // 解密方法
        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="cipherText"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public string Decrypt(string cipherText)
        {
            if (string.IsNullOrEmpty(cipherText))
                throw new ArgumentNullException(nameof(cipherText));

            using var aesAlg = Aes.Create();

            // 1. 还原标准Base64
            string standardBase64 = cipherText
                .Replace('-', '+')
                .Replace('_', '/');

            // 2. 补全Base64填充符（严格补全到4的倍数）
            while (standardBase64.Length % 4 != 0)
            {
                standardBase64 += '=';
            }

            // 3. 转换为字节数组
            byte[] cipherBytes;
            try
            {
                StringBuilder standardBase64new = new StringBuilder();
                //每5个字符添加一个+号，需要将每6个位置的地方+号去掉
                for (int i = 0; i < standardBase64.Length; i++){
                    if((i + 1) % 6 == 0 && standardBase64[i] == '+')
                    {
                        continue;
                    }
                    else
                    {
                        standardBase64new.Append(standardBase64[i]);
                    }
                }
                cipherBytes = Convert.FromBase64String(standardBase64new.ToString());
            }
            catch (FormatException ex)
            {
                throw new FormatException($"无效的Base64格式: {standardBase64}", ex);
            }

            _logger.LogDebug($"解密前密文总长度: {cipherBytes.Length} 字节");

            // 4. 验证总长度（至少32字节）
            if (cipherBytes.Length < aesAlg.BlockSize / 8 + aesAlg.BlockSize / 8)
            {
                throw new FormatException($"密文总长度({cipherBytes.Length})不足，至少需要32字节");
            }

            var keyBytes = GetValidKeyBytes(_encryptionKey, AesKeySize256);

            // 5. 提取IV
            var iv = new byte[aesAlg.BlockSize / 8];
            Array.Copy(cipherBytes, 0, iv, 0, iv.Length);

            // 6. 提取实际密文数据
            int cipherDataLength = cipherBytes.Length - iv.Length;
            _logger.LogDebug($"密文数据长度: {cipherDataLength} 字节");

            // 7. 关键验证：必须为16的倍数
            if (cipherDataLength % (aesAlg.BlockSize / 8) != 0)
            {
                throw new FormatException($"密文数据长度({cipherDataLength})不是16字节的整数倍");
            }

            var cipherData = new byte[cipherDataLength];
            Array.Copy(cipherBytes, iv.Length, cipherData, 0, cipherDataLength);

            // 8. 设置AES参数（与加密时完全一致）
            aesAlg.Key = keyBytes;
            aesAlg.IV = iv;
            aesAlg.Mode = CipherMode.CBC;
            aesAlg.Padding = PaddingMode.PKCS7;

            using var decryptor = aesAlg.CreateDecryptor();
            using var msDecrypt = new MemoryStream(cipherData);
            using var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);

            try
            {
                using var srDecrypt = new StreamReader(csDecrypt);
                string decrypted = srDecrypt.ReadToEnd();

                return decrypted;
            }
            catch (CryptographicException ex)
            {
                throw new InvalidDataException("解密失败，密钥或IV错误", ex);
            }
        }

        // 移除PKCS7填充
        private string RemovePkcs7Padding(string text)
        {
            if (string.IsNullOrEmpty(text))
                return text;

            int padding = text[text.Length - 1];
            if (padding < 1 || padding > 16)
                return text;

            return text.Substring(0, text.Length - padding);
        }
        /// <summary>
        /// 使用AES-GCM加密
        /// </summary>
        /// <param name="plainText"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ArgumentException"></exception>
        public static string EncryptWithAesGcm(string plainText, byte[] key)
        {
            if (string.IsNullOrEmpty(plainText))
                throw new ArgumentNullException(nameof(plainText));

            if (key == null || key.Length != 32) // 仅支持AES-256
                throw new ArgumentException("Key must be 256 bits (32 bytes).", nameof(key));

            using var aes = new AesGcm(key);

            // 生成随机Nonce (12 bytes for GCM)
            byte[] nonce = new byte[AesGcm.NonceByteSizes.MaxSize];
            RandomNumberGenerator.Fill(nonce);

            //// 生成随机附加认证数据(AAD)
            //byte[] aad = new byte[16];
            //RandomNumberGenerator.Fill(aad);

            // 转换明文为字节
            byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);

            // 分配密文和标签缓冲区
            byte[] cipherBytes = new byte[plainBytes.Length];
            byte[] tag = new byte[AesGcm.TagByteSizes.MaxSize];

            // 执行AEAD加密
            aes.Encrypt(nonce, plainBytes, cipherBytes, tag, null);

            // 组合Nonce + Tag + 密文
            using var ms = new MemoryStream();
            ms.Write(nonce, 0, nonce.Length);
            ms.Write(tag, 0, tag.Length);
            ms.Write(cipherBytes, 0, cipherBytes.Length);
            byte[] combined = ms.ToArray();

            // 转换为URL安全Base64 (保留填充)
            string base64 = Convert.ToBase64String(combined);
            return base64.Replace('+', '-').Replace('/', '_');
        }
        /// <summary>
        /// 使用AES-GCM解密
        /// </summary>
        /// <param name="cipherText"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        /// <exception cref="ArgumentException"></exception>
        public static string DecryptWithAesGcm(string cipherText, byte[] key)
        {
            if (string.IsNullOrEmpty(cipherText))
                throw new ArgumentNullException(nameof(cipherText));

            if (key == null || key.Length != 32)
                throw new ArgumentException("Key must be 256 bits (32 bytes).", nameof(key));

            try
            {
                // 还原Base64格式
                string base64 = cipherText.Replace('-', '+').Replace('_', '/');
                byte[] combined = Convert.FromBase64String(base64);

                // 拆分数据段
                int nonceLength = AesGcm.NonceByteSizes.MaxSize;
                int tagLength = AesGcm.TagByteSizes.MaxSize;
                int cipherLength = combined.Length - nonceLength - tagLength;

                if (cipherLength < 0)
                    throw new ArgumentException("Invalid ciphertext format.", nameof(cipherText));

                byte[] nonce = new byte[nonceLength];
                byte[] tag = new byte[tagLength];
                byte[] cipherBytes = new byte[cipherLength];

                Array.Copy(combined, 0, nonce, 0, nonceLength);
                Array.Copy(combined, nonceLength, tag, 0, tagLength);
                Array.Copy(combined, nonceLength + tagLength, cipherBytes, 0, cipherLength);

                using var aes = new AesGcm(key);
                byte[] plainBytes = new byte[cipherBytes.Length];

                // 执行AEAD解密（验证标签）
                aes.Decrypt(nonce, cipherBytes, tag, plainBytes, null);
                return Encoding.UTF8.GetString(plainBytes);
            }
            catch (FormatException ex)
            {
                throw new ArgumentException("Invalid Base64 format.", nameof(cipherText), ex);
            }
            catch (CryptographicException ex)
            {
                throw new SecurityException("Decryption failed: authentication tag mismatch or invalid key.", ex);
            }
        }

        // 生成32字节的随机密钥
        /// <summary>
        /// 生成32字节的随机密钥
        /// </summary>
        /// <returns></returns>
        public static byte[] GenerateKey()
        {
            byte[] key = new byte[32];
            using var rng = RandomNumberGenerator.Create();
            rng.GetBytes(key);
            return key;
        }
        // 辅助方法：确保密钥长度正确
        /// <summary>
        /// 辅助方法：确保密钥长度正确
        /// </summary>
        /// <param name="key"></param>
        /// <param name="targetLength"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        private byte[] GetValidKeyBytes(string key, int targetLength)
        {
            if (string.IsNullOrEmpty(key))
                throw new ArgumentNullException(nameof(key));

            // 如果密钥长度不足，填充0；如果过长，截断
            var keyBytes = new byte[targetLength];
            var inputBytes = Encoding.UTF8.GetBytes(key);

            Array.Copy(
                sourceArray: inputBytes,
                destinationArray: keyBytes,
                length: Math.Min(inputBytes.Length, targetLength));

            return keyBytes;
        }
        /// <summary>
        ///  派生密钥
        /// </summary>
        /// <param name="password"></param>
        /// <param name="targetLength"></param>
        /// <param name="salt"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static byte[] DeriveKey(string password, int targetLength, byte[] salt = null)
        {
            if (string.IsNullOrEmpty(password))
                throw new ArgumentNullException(nameof(password));

            // 使用安全的密钥派生函数PBKDF2
            using var rfc2898 = new Rfc2898DeriveBytes(
                password: password,
                salt: salt ?? new byte[16], // 若未提供盐值，使用默认值
                iterations: 100000, // 迭代次数，增强安全性
                hashAlgorithm: HashAlgorithmName.SHA256);

            return rfc2898.GetBytes(targetLength);
        }
        /// <summary>
        /// 格式化密钥字符串
        /// </summary>
        /// <param name="key">待格式化的密钥</param>
        /// <param name="removeDashes">true表示移除连字符并补全Base64填充；false表示添加连字符进行分组显示</param>
        /// <returns>格式化后的密钥字符串</returns>
        private string FormatKey(string key, bool removeDashes = false)
        {
            if (string.IsNullOrEmpty(key))
                return key;
            string cleanKey = key.Replace('-', '+').Replace('_', '/');
            if (removeDashes)
            {
                //还原
                cleanKey = key.Replace('+', '-').Replace('/', '_');
                //// 必须补全Base64填充
                //while (cleanKey.Length % 4 != 0)
                //{
                //    cleanKey += '=';
                //}
                return cleanKey;
            }
            else
            {
                // 先补全等号
                string paddedKey = cleanKey;
                //while (paddedKey.Length % 4 != 0)
                //{
                //    paddedKey += "=";
                //}

                // 分离数据部分和填充部分
                int equalsIndex = paddedKey.IndexOf('=');
                if (equalsIndex < 0) equalsIndex = paddedKey.Length;

                string dataPart = paddedKey.Substring(0, equalsIndex);
                string paddingPart = paddedKey.Substring(equalsIndex);

                // 对数据部分分组
                string formattedData = Regex.Replace(dataPart, ".{5}", "$0-").TrimEnd('-');

                return formattedData + paddingPart;
            }

        }
        //private string FormatKey(string key, bool removeDashes = false)
        //{
        //    if (string.IsNullOrEmpty(key))
        //        return key;

        //    if (removeDashes)
        //    {
        //        // 解密前处理：还原标准Base64
        //        string cleanKey = key.Replace('-', '+').Replace('_', '/');
        //        while (cleanKey.Length % 4 != 0)
        //        {
        //            cleanKey += '=';
        //        }
        //        return cleanKey;
        //    }
        //    else
        //    {
        //        // 补全等号以确定填充位置
        //        string paddedKey = key;
        //        while (paddedKey.Length % 4 != 0)
        //        {
        //            paddedKey += '=';
        //        }

        //        // 分离数据部分和填充部分
        //        int paddingIndex = paddedKey.IndexOf('=');
        //        if (paddingIndex < 0) paddingIndex = paddedKey.Length;

        //        string dataPart = paddedKey.Substring(0, paddingIndex);
        //        string paddingPart = paddedKey.Substring(paddingIndex);

        //        // 对数据部分每5个字符添加一个连字符（不影响合法连字符）
        //        if (dataPart.Length <= 5)
        //            return dataPart + paddingPart;

        //        StringBuilder formatted = new StringBuilder();
        //        int groupCount = 0;

        //        //for (int i = 0; i < dataPart.Length; i++)
        //        //{
        //        //    // 每5个非连字符字符后添加一个连字符
        //        //    if (i > 0 && dataPart[i] != '-' && groupCount % 5 == 0)
        //        //    {
        //        //        formatted.Append('-');
        //        //    }

        //        //    formatted.Append(dataPart[i]);

        //        //    // 只统计非连字符字符
        //        //    if (dataPart[i] != '-')
        //        //    {
        //        //        groupCount++;
        //        //    }
        //        //}

        //        for(int i =1; i < dataPart.Length; i++){
        //            if(i% 5 == 0)
        //            {
        //                formatted.Append('-');
        //            }
        //            formatted.Append(dataPart[i]);
        //        }

        //        return formatted.ToString() + paddingPart;
        //    }
        //}
        /// <summary>
        /// 验证产品密钥
        /// </summary>
        /// <param name="productKey"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        bool IActivationService.IsValidProductKey(string productKey)
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// 验证激活
        /// </summary>
        /// <param name="machineInfo"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        bool IActivationService.IsActivated(MachineInfo machineInfo)
        {
            throw new NotImplementedException();
        }
    }
}
